﻿//******************************************************************************************************
//  SubscriberUserControl.xaml.cs - Gbtc
//
//  Copyright © 2010, Grid Protection Alliance.  All Rights Reserved.
//
//  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
//  the NOTICE file distributed with this work for additional information regarding copyright ownership.
//  The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
//  not use this file except in compliance with the License. You may obtain a copy of the License at:
//
//      http://www.opensource.org/licenses/eclipse-1.0.php
//
//  Unless agreed to in writing, the subject software distributed under the License is distributed on an
//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
//  License for the specific language governing permissions and limitations.
//
//  Code Modification History:
//  ----------------------------------------------------------------------------------------------------
//  05/19/2011 - Magdiel Lorenzo
//       Generated original version of source code.
//  05/19/2011 - Mehulbhai P Thakkar
//       Added code regions, comments etc.
//  05/25/2011 - J. Ritchie Carroll
//       Attached to before save event so class could import new keyIV's into local crypto cache.
//  07/16/2012 - Alex Foglia
//       Modified some controls' properties upon user's role so he/she would or wouldn't be able to
//       modify their contents.
//
//******************************************************************************************************

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Xml.Linq;
using GSF.IO;
using Microsoft.Win32;
using SIEGate.UI.DataModels;
using SIEGate.UI.ViewModels;
using GSF.TimeSeries.UI;
using GSF;
using GSF.Data;

namespace SIEGate.UI.UserControls
{
    /// <summary>
    /// Interaction logic for SubscriberUserControl.xaml
    /// </summary>
    public partial class SubscriberUserControl : UserControl
    {
        #region [ Members ]

        private Subscribers m_dataContext;

        #endregion

        #region [ Constructors ]

        /// <summary>
        /// Creates an instance of <see cref="SubscriberUserControl"/>.
        /// </summary>
        public SubscriberUserControl()
        {
            InitializeComponent();
            this.Loaded += SubscriberUserControl_Loaded;
            this.Unloaded += SubscriberUserControl_Unloaded;
            m_dataContext = new Subscribers(10);
            this.DataContext = m_dataContext;
            m_dataContext.BeforeSave += DataContext_BeforeSave;
            m_dataContext.PropertyChanged += DataContext_PropertyChanged;
        }

        #endregion

        #region [ Methods ]

        /// <summary>
        /// Handles loaded event for <see cref="SubscriberUserControl"/>.
        /// </summary>
        /// <param name="sender">Source of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void SubscriberUserControl_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                using (AdoDataConnection database = new AdoDataConnection(CommonFunctions.DefaultSettingsCategory))
                {
                    Dictionary<string, string> settings = database.ServiceConnectionString().ParseKeyValuePairs();
                    IPAddress[] hostIPs = null;
                    IEnumerable<IPAddress> localIPs;

                    if (settings.ContainsKey("server"))
                        hostIPs = Dns.GetHostAddresses(settings["server"].Split(':')[0]);

                    localIPs = Dns.GetHostAddresses("localhost").Concat(Dns.GetHostAddresses(Dns.GetHostName()));

                    // Check to see if entered host name corresponds to a local IP address
                    if ((object)hostIPs == null)
                        MessageBox.Show("Failed to find service host address. Secure key exchange may not succeed." + Environment.NewLine + "Please make sure to run manager application with administrative privileges on the server where service is hosted.", "Authorize Subcriber", MessageBoxButton.OK, MessageBoxImage.Warning);
                    else if (!hostIPs.Any(localIPs.Contains))
                        MessageBox.Show("Secure key exchange may not succeed." + Environment.NewLine + "Please make sure to run manager application with administrative privileges on the server where service is hosted.", "Authorize Subscriber", MessageBoxButton.OK, MessageBoxImage.Warning);
                }

                // If the user is not an Administrator, then the following properties for these controls are readonly and not enable
                bool isAdmin = CommonFunctions.CurrentPrincipal.IsInRole("Administrator");

                AcronymField.IsReadOnly = !isAdmin;
                NameField.IsReadOnly = !isAdmin;
                RemoteCertificateField.IsReadOnly = !isAdmin;
                ValidIpAddressesField.IsReadOnly = !isAdmin;
                InternalRadioButton.IsEnabled = isAdmin;
                ExternalRadioButton.IsEnabled = isAdmin;
                EnablePGConnection.IsEnabled = isAdmin;
                ButtonClick.IsEnabled = isAdmin;
                FooterControl.IsEnabled = isAdmin;
            }
            catch
            {
                MessageBox.Show("Please make sure to run manager application with administrative privileges on the server where service is hosted.", "Authorize Subscriber", MessageBoxButton.OK, MessageBoxImage.Warning);
            }
        }

        /// <summary>
        /// Handles unloaded event for <see cref="SubscriberUserControl"/>.
        /// </summary>
        /// <param name="sender">Source of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void SubscriberUserControl_Unloaded(object sender, RoutedEventArgs e)
        {
            m_dataContext.ProcessPropertyChange();
            m_dataContext.BeforeSave -= DataContext_BeforeSave;
            m_dataContext.PropertyChanged -= DataContext_PropertyChanged;
        }

        private void DataContext_BeforeSave(object sender, CancelEventArgs cancelEventArgs)
        {
            string publisherCategory = m_dataContext.CurrentItem.Internal ? "internaldatapublisher" : "externaldatapublisher";
            string siegateConfigPath = FilePath.GetAbsolutePath("SIEGate.exe.config");

            XDocument config;
            XElement publisherElement;
            XElement trustedCertificatesPathElement;
            string trustedCertificatesPath = null;

            if (SelfSignedCheckbox.IsChecked == true)
            {
                // If remote certificate is self-signed, ensure that we expect
                // UntrustedRoot error to occur during certificate validation
                m_dataContext.CurrentItem.ValidPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors;
                m_dataContext.CurrentItem.ValidChainFlags |= X509ChainStatusFlags.UntrustedRoot;
            }

            if ((object)m_dataContext.RemoteCertificateTempPath != null && File.Exists(m_dataContext.RemoteCertificateTempPath) && File.Exists(siegateConfigPath))
            {
                // If an srq file was imported to populate the fields on this page,
                // then we will need to copy the attached certificate file from the
                // temp folder to the correct location
                config = XDocument.Load(siegateConfigPath);
                publisherElement = config.Descendants(publisherCategory).FirstOrDefault() ?? new XElement("");
                trustedCertificatesPathElement = publisherElement.Elements().FirstOrDefault(element => (string)element.Attribute("name") == "TrustedCertificatesPath");

                if ((object)trustedCertificatesPathElement != null)
                    trustedCertificatesPath = (string)trustedCertificatesPathElement.Attribute("value");

                if ((object)trustedCertificatesPath != null)
                {
                    trustedCertificatesPath = FilePath.GetAbsolutePath(trustedCertificatesPath);
                    File.Move(m_dataContext.RemoteCertificateTempPath, Path.Combine(trustedCertificatesPath, m_dataContext.CurrentItem.RemoteCertificateFile));
                }
            }
        }

        private void DataContext_PropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
        {
            if (propertyChangedEventArgs.PropertyName == "CurrentItem")
            {
                if (m_dataContext.CurrentItem.Internal)
                    InternalRadioButton.IsChecked = true;
                else
                    ExternalRadioButton.IsChecked = true;

                m_dataContext.RemoteCertificateTempPath = null;
            }
        }

        private void InterfaceRadioButton_Checked(object sender, RoutedEventArgs e)
        {
            RadioButton interfaceRadioButton = sender as RadioButton;

            if ((object)interfaceRadioButton != null && (object)m_dataContext != null)
                m_dataContext.CurrentItem.Internal = (interfaceRadioButton.Content.ToString() == "Internal");
        }

        // Display popup message for the user
        private void Popup(string message, string caption, MessageBoxImage image)
        {
            MessageBox.Show(Application.Current.MainWindow, message, caption, MessageBoxButton.OK, image);
        }

        /// <summary>
        /// Handles preview key down event on datagrid.
        /// </summary>
        /// <param name="sender">Source of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void DataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Delete)
            {
                DataGrid dataGrid = sender as DataGrid;
                if (dataGrid.SelectedItems.Count > 0)
                {
                    if (MessageBox.Show("Are you sure you want to delete " + dataGrid.SelectedItems.Count + " selected item(s)?", "Delete Selected Items", MessageBoxButton.YesNo) == MessageBoxResult.No)
                        e.Handled = true;
                }
            }
        }

        /// <summary>
        /// Handles click event on button.
        /// </summary>
        /// <param name="sender">Source of the event.</param>
        /// <param name="e">Event arguments.</param>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            AuthenticationRequest request;
            string tempFilePath;

            openFileDialog.Filter = "Subscription Requests|*.srq|All Files|*.*";
            openFileDialog.DefaultExt = ".srq";

            if (openFileDialog.ShowDialog() == true)
            {
                using (FileStream requestStream = File.OpenRead(openFileDialog.FileName))
                {
                    request = Serialization.Deserialize<AuthenticationRequest>(requestStream, SerializationFormat.Binary);
                }

                Subscriber subscriber = new Subscriber()
                {
                    Acronym = request.Acronym.ToUpper(),
                    Name = request.Name,
                    RemoteCertificateFile = string.Format("{0}.cer", request.Acronym.ToUpper()),
                    ValidIPAddresses = request.ValidIPAddresses
                };

                m_dataContext.CurrentItem = subscriber;

                tempFilePath = Path.GetTempFileName();
                m_dataContext.RemoteCertificateTempPath = tempFilePath;
                File.WriteAllBytes(tempFilePath, request.CertificateFile);
            }
            else
            {
                e.Handled = true;
            }
        }

        private void DataGrid_Sorting(object sender, DataGridSortingEventArgs e)
        {
            m_dataContext.SortData(e.Column.SortMemberPath);
        }

        private void GridDetailView_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (m_dataContext.IsNewRecord)
                DataGridList.SelectedIndex = -1;
        }

        #endregion
    }
}
